#ifndef BOSS_Afterburner_RooFitBuilder_H
#define BOSS_Afterburner_RooFitBuilder_H

#include "Fit/RooArgusBESIII.h"
#include "RooAddPdf.h"
#include "RooArgusBG.h"
#include "RooBreitWigner.h"
#include "RooBreitWignerWave.h"
#include "RooChebychev.h"
#include "RooFFTConvPdf.h"
#include "RooGaussian.h"
#include "RooHistPdf.h"
#include "RooPolynomial.h"
#include "RooRealVar.h"
#include "RooTruncatedPolynomial.h"
#include "RooVoigtian.h"
#include <string>
#include <yaml-cpp/yaml.h>

/// @addtogroup Afterburner_objects
/// @{

struct FitModelObj
{
  RooAbsPdf*  pdf    = nullptr;
  RooRealVar* factor = nullptr;
  TString     name;
};

struct SigPlusBck
{
  FitModelObj sig;
  FitModelObj bck;
  RooArgList* sum   = nullptr;
  RooArgList* coeff = nullptr;
  RooRealVar* ratio = nullptr;
  RooAddPdf*  pdf   = nullptr;
};

/// @author   Remco de Boer 雷穆克 (r.e.deboer@students.uu.nl or remco.de.boer@ihep.ac.cn)
/// @date     May 2nd, 2019
class RooFitBuilder
{
public:
  RooFitBuilder(RooRealVar& var) : fVar(var) {}

  RooRealVar* BuildVar(const YAML::Node& input);

  RooBreitWigner*     BuildBreitWigner(const YAML::Node& input);
  RooGaussian*        BuildGaussian(const YAML::Node& input);
  RooAddPdf*          BuildGaussians(const YAML::Node& input);
  RooHistPdf*         BuildHistPdf(const YAML::Node& input);
  RooBreitWignerWave* BuildPwave(const YAML::Node& input);
  RooFFTConvPdf*      BuildConvolutedPwave(const YAML::Node& input);
  RooVoigtian*        BuildVoigtian(const YAML::Node& input);

  RooArgusBG*             BuildArgus(const YAML::Node& input);
  RooArgusBESIII*         BuildArgusBESIII(const YAML::Node& input);
  RooChebychev*           BuildChebychev(const YAML::Node& input);
  RooPolynomial*          BuildPolynomial(const YAML::Node& input);
  RooTruncatedPolynomial* BuildTruncatedPolynomial(const YAML::Node& input);

  RooFFTConvPdf* ConvolutePdf(RooAbsPdf* pdf1, RooAbsPdf* pdf2);
  RooAddPdf*     AddPdfs(RooArgList* pdfs, RooArgList* ratios);
  FitModelObj    BuildModel(const YAML::Node& input);
  SigPlusBck     BuildSigPlusBck(const YAML::Node& input);

private:
  RooRealVar& fVar;

  std::string ExtractName(const YAML::Node& input);
  static Int_t fID;
};
/// @}
#endif